home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume17 / zoo2 / part04 < prev    next >
Encoding:
Internet Message Format  |  1989-02-01  |  44.6 KB

  1. Subject:  v17i067:  Zoo archive program, Part04/10
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: Rahul Dhesi <bsu-cs!dhesi@iuvax.cs.indiana.edu>
  6. Posting-number: Volume 17, Issue 67
  7. Archive-name: zoo2/part04
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 4 (of 10)."
  16. # Wrapped by rsalz@papaya.bbn.com on Thu Feb  2 18:03:59 1989
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f 'lzc.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'lzc.c'\"
  20. else
  21. echo shar: Extracting \"'lzc.c'\" \(8454 characters\)
  22. sed "s/^X//" >'lzc.c' <<'END_OF_FILE'
  23. X#ifndef LINT
  24. Xstatic char sccsid[]="@(#) lzc.c 2.6 88/01/30 18:39:15";
  25. X#endif /* LINT */
  26. X
  27. X#include "options.h"
  28. X/*
  29. XLempel-Ziv compression.  Mostly based on Tom Pfau's assembly language
  30. Xcode.
  31. X
  32. XThe contents of this file are hereby released to the public domain.
  33. X
  34. X                                    -- Rahul Dhesi  1986/12/31
  35. X*/
  36. X
  37. X#include "zoo.h"
  38. X#include "zooio.h"
  39. X#include "various.h"
  40. X#include "zoofns.h"           /* function definitions */
  41. X/* zoomem.h defines IN_BUF_SIZE & OUT_BUF_SIZE */
  42. X#include "zoomem.h"
  43. X#include "debug.h"
  44. X#include "assert.h"
  45. X/* lzconst.h contains constants for lzd() and lzc() */
  46. X#include "lzconst.h"
  47. X
  48. X#ifdef LINT_ARGS
  49. Xvoid init_ctab(NOTHING);
  50. Xvoid wr_ccode(int);
  51. Xint rd_cch(NOTHING);
  52. Xint lukup_ccode(int, int, int *);
  53. Xvoid ad_ccode(int, int, int);
  54. Xvoid check_ratio(NOTHING);
  55. Xvoid flush_c(int);
  56. X#else
  57. Xvoid init_ctab();
  58. Xvoid wr_ccode();
  59. Xint rd_cch();
  60. Xint lukup_ccode();
  61. Xvoid ad_ccode();
  62. Xvoid check_ratio();
  63. Xvoid flush_c();
  64. X#endif
  65. X
  66. X/* interval at which to check ratio */
  67. X#define CHECKGAP 4000
  68. X#define NEXT_USE  1
  69. X#define FIRST_USE 2
  70. X#define FOUND 0
  71. X
  72. Xstruct   tabentry {
  73. X   int first;
  74. X   int next;
  75. X   char z_ch;
  76. X};
  77. X
  78. Xextern char *out_buf_adr;
  79. Xextern char *in_buf_adr;
  80. Xextern char memflag;                    /* memory allocated? */
  81. Xstruct tabentry *table;                 /* this table also used by lzd.c */
  82. Xstatic unsigned int free_code;
  83. Xstatic int nbits;
  84. Xstatic unsigned int max_code;
  85. Xstatic unsigned int bitsout;
  86. Xstatic int bit_interval;
  87. Xstatic unsigned int bytesin, ratio, ratflag;
  88. Xstatic unsigned int in_offset, in_size;
  89. Xstatic unsigned int bit_offset;
  90. X
  91. X#ifdef UNBUF_IO
  92. X#define        BLOCKFILE        int
  93. X#define        BLOCKREAD        read
  94. X#define        BLOCKWRITE        write
  95. Xint read PARMS ((int, VOIDPTR, unsigned));
  96. Xint write PARMS ((int, VOIDPTR, unsigned));
  97. X#else
  98. X#define        BLOCKFILE        ZOOFILE
  99. X#define        BLOCKREAD        zooread
  100. X#define        BLOCKWRITE        zoowrite
  101. X#endif /* UNBUF_IO */
  102. X
  103. Xstatic BLOCKFILE in_f, out_f;
  104. X
  105. Xint lzc (input_f, output_f)
  106. XBLOCKFILE input_f, output_f;
  107. X{
  108. X   int nextch, prefix_code, k;
  109. X   int status;
  110. X   int where;
  111. X
  112. X   in_f = input_f;
  113. X   out_f = output_f;
  114. X
  115. X   bit_offset = in_offset = in_size = 0;
  116. X
  117. X   if (memflag == 0) {
  118. X     table = (struct tabentry *) emalloc((MAXMAX+10) * sizeof(struct tabentry));
  119. X     memflag++;
  120. X   }
  121. X
  122. X   init_ctab();
  123. X   wr_ccode(CLEAR);
  124. X   nextch = rd_cch();
  125. X   if (nextch == EOF) {                  /* note real EOF, not Z_EOF */
  126. X      wr_ccode (Z_EOF);
  127. X        flush_c ((int) ((bit_offset + 7) / 8));
  128. X      return (0);                         /* normal return from compress */
  129. X   }
  130. X
  131. X   /* compression loop begins here with nextch holding the next input char */
  132. Xloop1:
  133. X   if (ratflag != 0)
  134. X      check_ratio();
  135. X   nextch &= 0xff;                       /* turn character to code */
  136. X   assert(nextch < 256);
  137. Xloop2:
  138. X   prefix_code = nextch;
  139. X   nextch = rd_cch();
  140. X   if (nextch == EOF) {                  /* note real EOF, not Z_EOF */
  141. X      wr_ccode (prefix_code);
  142. X      wr_ccode (Z_EOF);
  143. X        flush_c ((int) ((bit_offset + 7) / 8));
  144. X      return (0);                         /* normal return from compress */
  145. X   }
  146. X   nextch &= 0xff;                        /* force to 8 bits */
  147. X   assert(nextch < 256);
  148. X
  149. X   k = nextch;
  150. X   status = lukup_ccode (prefix_code, nextch, &where);
  151. X   if (status == FOUND) {
  152. X      nextch = where;                     /* where found */
  153. X      goto loop2;
  154. X   }
  155. X   assert(status == FIRST_USE || status == NEXT_USE);
  156. X
  157. X   /* reach here with status = FIRST_USE or NEXT_USE */
  158. X   ad_ccode (status, nextch, where);
  159. X
  160. X   wr_ccode (prefix_code);
  161. X   nextch = k;
  162. X
  163. X   if (free_code <= max_code)
  164. X      goto loop1;
  165. X   assert(nbits >= 9 && nbits <= MAXBITS);
  166. X   if (nbits >= MAXBITS) {
  167. X   /* To continue using table after it is full, remove next two lines */
  168. X      wr_ccode (CLEAR);
  169. X      init_ctab();
  170. X
  171. X      goto loop1;
  172. X   }
  173. X
  174. X   nbits++;
  175. X   assert(nbits >= 9 && nbits <= MAXBITS);
  176. X   max_code = max_code << 1;
  177. X   goto loop1;
  178. X} /* end lzc() */
  179. X
  180. Xvoid wr_ccode (code)
  181. Xint code;
  182. X{
  183. X   unsigned int ofs_inbyte, hibits;
  184. X   int byte_offset;
  185. X
  186. X#ifdef DEBUG
  187. Xif (code == CLEAR)
  188. X   printf(" CLEAR\n");
  189. X#endif
  190. X
  191. X   assert(nbits >= 9 && nbits <= MAXBITS);
  192. X   bitsout += nbits;                /* total number of bits written */
  193. X   bit_interval -= nbits;
  194. X   if (bit_interval < 0)
  195. X      ratflag = 1;                  /* time to check ratio */
  196. X
  197. X   byte_offset = bit_offset / 8;
  198. X   ofs_inbyte = bit_offset % 8;     /* offset within byte */
  199. X   bit_offset += nbits;             /* allowing for new code */
  200. X
  201. X   if (byte_offset >= OUTBUFSIZ - 4) {
  202. X      flush_c (byte_offset);
  203. X      bit_offset = ofs_inbyte + nbits;
  204. X      out_buf_adr[0] = out_buf_adr [byte_offset];
  205. X      byte_offset = 0;
  206. X   }
  207. X
  208. X   code = code & 0xffff;            /* force to 16 bits */
  209. X
  210. X   if (ofs_inbyte == 0)
  211. X      out_buf_adr[byte_offset]  = code & 0xff;
  212. X   else
  213. X      out_buf_adr[byte_offset] |= (code << ofs_inbyte) & 0xff;
  214. X
  215. X   hibits = ((unsigned int) code) >> (8 - ofs_inbyte);
  216. X   out_buf_adr[byte_offset+1] = hibits & 0xff;
  217. X   out_buf_adr[byte_offset+2] = (((unsigned int) hibits) >> 8) & 0xff;
  218. X
  219. X   assert(nbits >= 9 && nbits <= MAXBITS);
  220. X} /* end wr_ccode() */
  221. X
  222. Xvoid init_ctab()
  223. X{
  224. X   int i;
  225. X   bytesin = bitsout = ratio = ratflag = 0;
  226. X   bit_interval = CHECKGAP;
  227. X   nbits = 9;
  228. X   max_code = 512;
  229. X#ifdef COMMENT
  230. X   for (i = 0; i < 256; i++) {
  231. X#endif
  232. X   for (i = 0; i < MAXMAX+1; i++) {
  233. X      table[i].z_ch = table[i].first = table[i].next = -1;
  234. X   }
  235. X#ifdef COMMENT
  236. X   /*DEBUG*/ table[MAXMAX].first   = table[MAXMAX].next = -1;
  237. X   /*DEBUG*/ table[MAXMAX-1].first = table[MAXMAX-1].next = -1;
  238. X#endif
  239. X   free_code = FIRST_FREE;
  240. X} /* end init_ctab() */
  241. X
  242. Xint rd_cch()
  243. X{
  244. X   int count;
  245. X   bytesin++;
  246. X   if (in_offset == in_size) {
  247. X      count = BLOCKREAD (in_f, in_buf_adr, INBUFSIZ);
  248. X      if (count == -1)
  249. X         prterror ('f', "Error reading input file during compression.\n");
  250. X      addbfcrc (in_buf_adr, count);
  251. X      if (count == 0) {
  252. X         debug((printf("\nEOF on input\n")))
  253. X         return (EOF);              /* real EOF, not Z_EOF */
  254. X      }
  255. X      in_size = count;
  256. X      debug((printf("\ninput %d chars\n", count)))
  257. X      in_offset = 0;
  258. X   }
  259. X   in_offset++;
  260. X   return (in_buf_adr[in_offset-1] & 0xff);
  261. X} /* end rd_cch () */
  262. X
  263. Xvoid check_ratio()
  264. X{
  265. X#ifdef COMMENT
  266. X   int rat;
  267. X   if (bitsout > 16383) {     /* avoid overflow */
  268. X      bitsout /= 4;
  269. X      bytesin /= 4;
  270. X   }
  271. X   rat = (2 * bitsout) / bytesin;
  272. X   if (1.1 * rat < ratio) {
  273. X      printf("#");
  274. X      wr_ccode (CLEAR);
  275. X      init_ctab();
  276. X      bit_interval = CHECKGAP;
  277. X      bitsout = 0;
  278. X      bytesin = 0;
  279. X      ratio = 0;
  280. X   } else
  281. X      ratio = ((ratio << 2) + ((2 * bitsout) / bytesin)) / 5;
  282. X#else
  283. X   bit_interval = CHECKGAP;
  284. X   bitsout = 0;
  285. X   bytesin = 0;
  286. X#endif
  287. X} /* end check_ratio() */
  288. X
  289. Xvoid ad_ccode (status, ch, index)
  290. Xint status, index, ch;
  291. X{
  292. X   assert(status == FIRST_USE || status == NEXT_USE);
  293. X#ifdef COMMENT
  294. X   if (free_code >= MAXMAX)      /* to fix apparent bug in original */
  295. X      return;
  296. X#endif
  297. X#ifdef COMMENT
  298. X   if (status == NEXT_USE)
  299. X      table[index].next = free_code;
  300. X   else                 /* else must be FIRST_USE */
  301. X      table[index].first = free_code;
  302. X#endif
  303. X   if (status == NEXT_USE)
  304. X      table[index].next = (free_code >= MAXMAX ? -1 : free_code);
  305. X   else                 /* else must be FIRST_USE */
  306. X      table[index].first = (free_code >= MAXMAX ? -1 : free_code);
  307. X
  308. X#ifdef COMMENT
  309. X   if (free_code < MAXMAX) {
  310. X#endif
  311. X   if (free_code <= MAXMAX) {
  312. X      table[free_code].first = table[free_code].next = -1;
  313. X      table[free_code].z_ch = ch & 0xff;
  314. X      free_code++;
  315. X   }
  316. X} /* end ad_ccode() */
  317. X
  318. Xint lukup_ccode (index, ch, where)
  319. Xint index;                        /* where to start looking */
  320. Xint ch;                             /* char to look for */
  321. Xint *where;                       /* last entry looked at */
  322. X{
  323. X   *where = index;
  324. X   index = table[index].first;
  325. X   if (index == -1) {
  326. X      return (FIRST_USE);           /* not found, first use */
  327. X   } else {
  328. X      while (1) {
  329. X         if ((table[index].z_ch & 0xff) == (ch & 0xff)) {
  330. X            *where = index;
  331. X            return (FOUND);
  332. X         }
  333. X         *where = index;
  334. X         index = table[index].next;
  335. X         if (index == -1) {
  336. X            return (NEXT_USE);
  337. X         }
  338. X      } /* end while */
  339. X   } /* end else */
  340. X} /* end lukup_ccode() */
  341. X
  342. Xvoid flush_c (count)
  343. Xint count;
  344. X{
  345. X   int status;
  346. X#ifdef DEBUG
  347. Xprintf(" <flushed %d bytes> ", count);
  348. X#endif
  349. X    if (count != 0) {
  350. X        status = BLOCKWRITE (out_f, out_buf_adr, count);
  351. X        if (status == -1)
  352. X            prterror ('f', "Error writing during compression.\n");
  353. X    }
  354. X}
  355. END_OF_FILE
  356. if test 8454 -ne `wc -c <'lzc.c'`; then
  357.     echo shar: \"'lzc.c'\" unpacked with wrong size!
  358. fi
  359. # end of 'lzc.c'
  360. fi
  361. if test -f 'lzd.c' -a "${1}" != "-c" ; then 
  362.   echo shar: Will not clobber existing file \"'lzd.c'\"
  363. else
  364. echo shar: Extracting \"'lzd.c'\" \(7771 characters\)
  365. sed "s/^X//" >'lzd.c' <<'END_OF_FILE'
  366. X#ifndef LINT
  367. Xstatic char sccsid[]="@(#) lzd.c 2.6 88/01/30 20:39:18";
  368. X#endif /* LINT */
  369. X
  370. X#include "options.h"
  371. X/*
  372. XLempel-Ziv decompression.  Mostly based on Tom Pfau's assembly language
  373. Xcode.  The contents of this file are hereby released to the public domain.
  374. X                                 -- Rahul Dhesi 1986/11/14
  375. X*/
  376. X
  377. X#include "zoo.h"
  378. X#include "zooio.h"
  379. X#include "various.h"
  380. X#include "zoofns.h"           /* function definitions */
  381. X/* zoomem.h defines IN_BUF_SIZE & OUT_BUF_SIZE */
  382. X#include "zoomem.h"
  383. X#include "debug.h"
  384. X#include "assert.h"
  385. X/* lzconst.h contains constants for lzd() and lzc() */
  386. X#include "lzconst.h"
  387. X
  388. X#define  STACKSIZE   4000
  389. X
  390. Xstruct tabentry {
  391. X   unsigned next;
  392. X   char z_ch;
  393. X};
  394. X
  395. X
  396. X#ifdef LINT_ARGS
  397. Xvoid init_dtab(NOTHING);
  398. Xunsigned rd_dcode(NOTHING);
  399. Xvoid wr_dchar (char);
  400. Xvoid ad_dcode(NOTHING);
  401. X#else
  402. Xvoid init_dtab();
  403. Xunsigned rd_dcode();
  404. Xvoid wr_dchar();
  405. Xvoid ad_dcode();
  406. X#endif
  407. X
  408. X#ifdef FILTER
  409. X/* to send data back to zoofilt */
  410. Xextern unsigned int filt_lzd_word;
  411. X#endif /* FILTER */
  412. X
  413. X
  414. Xstatic unsigned stack_pointer = 0;
  415. Xstatic unsigned *stack;
  416. X
  417. X#define  push(x)  {  \
  418. X                     stack[stack_pointer++] = (x);                   \
  419. X                     if (stack_pointer >= STACKSIZE)                 \
  420. X                        prterror ('f', "Stack overflow in lzd().\n");\
  421. X                  }
  422. X#define  pop()    (stack[--stack_pointer])
  423. X
  424. Xextern char *out_buf_adr;        /* output buffer */
  425. Xextern char *in_buf_adr;         /* input buffer */
  426. X
  427. Xchar memflag = 0;                /* memory allocated? flag */
  428. Xextern struct tabentry *table;   /* hash table from lzc.c */
  429. Xstatic unsigned cur_code;
  430. Xstatic unsigned old_code;
  431. Xstatic unsigned in_code;
  432. X
  433. Xstatic unsigned free_code;
  434. Xstatic int nbits;
  435. Xstatic unsigned max_code;
  436. X
  437. Xstatic char fin_char;
  438. Xstatic char k;
  439. Xstatic unsigned masks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
  440. X                        0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff };
  441. Xstatic unsigned bit_offset;
  442. Xstatic unsigned output_offset;
  443. X
  444. X#ifdef UNBUF_IO
  445. X#define        BLOCKFILE        int
  446. X#define        BLOCKREAD        read
  447. X#define        BLOCKWRITE        blockwrite
  448. Xint read PARMS ((int, VOIDPTR, unsigned));
  449. Xint write PARMS ((int, VOIDPTR, unsigned));
  450. X#else
  451. X#define        BLOCKFILE        ZOOFILE
  452. X#define        BLOCKREAD        zooread
  453. X#define        BLOCKWRITE        zoowrite
  454. X#endif /* UNBUF_IO */
  455. X
  456. Xstatic BLOCKFILE in_f, out_f; 
  457. X
  458. Xint lzd(input_f, output_f)
  459. XBLOCKFILE input_f, output_f;          /* input & output file handles */
  460. X{
  461. X   in_f = input_f;                 /* make it avail to other fns */
  462. X   out_f = output_f;               /* ditto */
  463. X   nbits = 9;
  464. X   max_code = 512;
  465. X   free_code = FIRST_FREE;
  466. X   stack_pointer = 0;
  467. X   bit_offset = 0;
  468. X   output_offset = 0;
  469. X
  470. X   if (BLOCKREAD (in_f, in_buf_adr, INBUFSIZ) == -1)
  471. X      return(IOERR);
  472. X   if (memflag == 0) {
  473. X     table = (struct tabentry *) emalloc((MAXMAX+10) * sizeof(struct tabentry));
  474. X     stack = (unsigned *) emalloc (sizeof (unsigned) * STACKSIZE + 20);
  475. X     memflag++;
  476. X   }
  477. X
  478. X   init_dtab();             /* initialize table */
  479. X
  480. Xloop:
  481. X   cur_code = rd_dcode();
  482. Xgoteof: /* special case for CLEAR then Z_EOF, for 0-length files */
  483. X   if (cur_code == Z_EOF) {
  484. X      debug((printf ("lzd: Z_EOF\n")))
  485. X      if (output_offset != 0) {
  486. X         if (BLOCKWRITE (out_f, out_buf_adr, output_offset) != output_offset)
  487. X            prterror ('f', "Output error in lzd().\n");
  488. X         addbfcrc(out_buf_adr, output_offset);
  489. X      }
  490. X#ifdef FILTER
  491. X        /* get next two bytes and put them where zoofilt can find them */
  492. X        /* nbits known to be in range 9..13 */
  493. X        bit_offset = ((bit_offset + 7) / 8) * 8; /* round up to next byte */
  494. X        filt_lzd_word = rd_dcode();
  495. X        filt_lzd_word |= (rd_dcode() << nbits);
  496. X        filt_lzd_word &= 0xffff;
  497. X#endif
  498. X      return (0);
  499. X   }
  500. X
  501. X   assert(nbits >= 9 && nbits <= 13);
  502. X
  503. X   if (cur_code == CLEAR) {
  504. X      debug((printf ("lzd: CLEAR\n")))
  505. X      init_dtab();
  506. X      fin_char = k = old_code = cur_code = rd_dcode();
  507. X        if (cur_code == Z_EOF)        /* special case for 0-length files */
  508. X            goto goteof;
  509. X      wr_dchar(k);
  510. X      goto loop;
  511. X   }
  512. X
  513. X   in_code = cur_code;
  514. X   if (cur_code >= free_code) {        /* if code not in table (k<w>k<w>k) */
  515. X      cur_code = old_code;             /* previous code becomes current */
  516. X      push(fin_char);
  517. X   }
  518. X
  519. X   while (cur_code > 255) {               /* if code, not character */
  520. X      push(table[cur_code].z_ch);         /* push suffix char */
  521. X      cur_code = table[cur_code].next;    /* <w> := <w>.code */
  522. X   }
  523. X
  524. X   assert(nbits >= 9 && nbits <= 13);
  525. X
  526. X   k = fin_char = cur_code;
  527. X   push(k);
  528. X   while (stack_pointer != 0) {
  529. X      wr_dchar(pop());
  530. X   }
  531. X   assert(nbits >= 9 && nbits <= 13);
  532. X   ad_dcode();
  533. X   old_code = in_code;
  534. X
  535. X   assert(nbits >= 9 && nbits <= 13);
  536. X
  537. X   goto loop;
  538. X} /* lzd() */
  539. X
  540. X/* rd_dcode() reads a code from the input (compressed) file and returns
  541. Xits value. */
  542. Xunsigned rd_dcode()
  543. X{
  544. X   register char *ptra, *ptrb;    /* miscellaneous pointers */
  545. X   unsigned word;                     /* first 16 bits in buffer */
  546. X   unsigned byte_offset;
  547. X   char nextch;                           /* next 8 bits in buffer */
  548. X   unsigned ofs_inbyte;               /* offset within byte */
  549. X
  550. X   ofs_inbyte = bit_offset % 8;
  551. X   byte_offset = bit_offset / 8;
  552. X   bit_offset = bit_offset + nbits;
  553. X
  554. X   assert(nbits >= 9 && nbits <= 13);
  555. X
  556. X   if (byte_offset >= INBUFSIZ - 5) {
  557. X      int space_left;
  558. X
  559. X      assert(byte_offset >= INBUFSIZ - 5);
  560. X      debug((printf ("lzd: byte_offset near end of buffer\n")))
  561. X
  562. X      bit_offset = ofs_inbyte + nbits;
  563. X      space_left = INBUFSIZ - byte_offset;
  564. X      ptrb = byte_offset + in_buf_adr;          /* point to char */
  565. X      ptra = in_buf_adr;
  566. X      /* we now move the remaining characters down buffer beginning */
  567. X      debug((printf ("rd_dcode: space_left = %d\n", space_left)))
  568. X      while (space_left > 0) {
  569. X         *ptra++ = *ptrb++;
  570. X         space_left--;
  571. X      }
  572. X      assert(ptra - in_buf_adr == ptrb - (in_buf_adr + byte_offset));
  573. X      assert(space_left == 0);
  574. X      if (BLOCKREAD (in_f, ptra, byte_offset) == -1)
  575. X         prterror ('f', "I/O error in lzd:rd_dcode.\n");
  576. X      byte_offset = 0;
  577. X   }
  578. X   ptra = byte_offset + in_buf_adr;
  579. X   /* NOTE:  "word = *((int *) ptra)" would not be independent of byte order. */
  580. X   word = (unsigned char) *ptra; ptra++;
  581. X   word = word | ( ((unsigned char) *ptra) << 8 ); ptra++;
  582. X
  583. X   nextch = *ptra;
  584. X   if (ofs_inbyte != 0) {
  585. X      /* shift nextch right by ofs_inbyte bits */
  586. X      /* and shift those bits right into word; */
  587. X      word = (word >> ofs_inbyte) | (((unsigned)nextch) << (16-ofs_inbyte));
  588. X   }
  589. X   return (word & masks[nbits]); 
  590. X} /* rd_dcode() */
  591. X
  592. Xvoid init_dtab()
  593. X{
  594. X   nbits = 9;
  595. X   max_code = 512;
  596. X   free_code = FIRST_FREE;
  597. X}
  598. X
  599. Xvoid wr_dchar (ch)
  600. Xchar ch;
  601. X{
  602. X   if (output_offset >= OUTBUFSIZ) {      /* if buffer full */
  603. X      if (BLOCKWRITE (out_f, out_buf_adr, output_offset) != output_offset)
  604. X         prterror ('f', "Write error in lzd:wr_dchar.\n");
  605. X      addbfcrc(out_buf_adr, output_offset);     /* update CRC */
  606. X      output_offset = 0;                  /* restore empty buffer */
  607. X   }
  608. X   assert(output_offset < OUTBUFSIZ);
  609. X   out_buf_adr[output_offset++] = ch;        /* store character */
  610. X} /* wr_dchar() */
  611. X
  612. X/* adds a code to table */
  613. Xvoid ad_dcode()
  614. X{
  615. X   assert(nbits >= 9 && nbits <= 13);
  616. X   assert(free_code <= MAXMAX+1);
  617. X   table[free_code].z_ch = k;                /* save suffix char */
  618. X   table[free_code].next = old_code;         /* save prefix code */
  619. X   free_code++;
  620. X   assert(nbits >= 9 && nbits <= 13);
  621. X   if (free_code >= max_code) {
  622. X      if (nbits < MAXBITS) {
  623. X         debug((printf("lzd: nbits was %d\n", nbits)))
  624. X         nbits++;
  625. X         assert(nbits >= 9 && nbits <= 13);
  626. X         debug((printf("lzd: nbits now %d\n", nbits)))
  627. X         max_code = max_code << 1;        /* double max_code */
  628. X         debug((printf("lzd: max_code now %d\n", max_code)))
  629. X      }
  630. X   }
  631. X}
  632. END_OF_FILE
  633. if test 7771 -ne `wc -c <'lzd.c'`; then
  634.     echo shar: \"'lzd.c'\" unpacked with wrong size!
  635. fi
  636. # end of 'lzd.c'
  637. fi
  638. if test -f 'needed.c' -a "${1}" != "-c" ; then 
  639.   echo shar: Will not clobber existing file \"'needed.c'\"
  640. else
  641. echo shar: Extracting \"'needed.c'\" \(8256 characters\)
  642. sed "s/^X//" >'needed.c' <<'END_OF_FILE'
  643. X#ifndef LINT
  644. Xstatic char sccsid[]="@(#) needed.c 2.16 88/01/31 15:54:37";
  645. X#endif /* LINT */
  646. X
  647. X/*
  648. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  649. X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
  650. X*/
  651. X
  652. X#define    STRCMP(s1,op,s2)        (strcmp(s1,s2) op 0)
  653. X
  654. X#include "options.h"
  655. X/* Accepts a filename from an archive and returns 1 if a command-line
  656. X   argument filename matches it.  Otherwise returns 0. Returns
  657. X   1 if no arguments were supplied (so by default, all files will
  658. X   be extracted */
  659. X
  660. X#include "zoo.h"
  661. X
  662. X#ifdef NEEDCTYP
  663. X#include <ctype.h>              /* for tolower() */
  664. X#else
  665. X#include "portable.h"
  666. X#endif
  667. X
  668. X#include "zooio.h"
  669. X#include "zoofns.h"
  670. X#include "various.h"
  671. X#include "debug.h"
  672. X
  673. Xextern int next_arg;          /* filenames start at this position */
  674. Xextern int arg_count;         /* count of arguments supplied to program */
  675. Xextern char **arg_vector;     /* vector of arguments supplied to program */
  676. X/* Uses FIRST_ARG in zoo.h, so must be recompiled when switching
  677. X   between Ooz and Zoo */
  678. X
  679. Xint needed(pathname, direntry, header)
  680. Xchar *pathname;
  681. Xstruct direntry *direntry;
  682. Xstruct zoo_header *header;
  683. X{
  684. X   register int i;
  685. X   register char *arg;
  686. X   char *justname;
  687. X    char arg_copy[PATHSIZE];                /* working copy of an argument */
  688. X    char path_copy[PATHSIZE];                /* working copy of pathname */
  689. X    char *p;                                        /* a temporary pointer */
  690. X    char *q;                                        /* a temporary pointer */
  691. X
  692. X    /* if no filenames supplied, match latest version of each 
  693. X        (but match any version if versions not enabled) */
  694. X   if (arg_count <= FIRST_ARG &&
  695. X            (!(header->vdata & VFL_ON) || 
  696. X            !(direntry->vflag & VFL_ON) || (direntry->vflag & VFL_LAST))) {
  697. X         
  698. X      return (1);                       /* .. then all files are needed */
  699. X    }
  700. X
  701. X   /* count backwards and stop if '+' is encountered */
  702. X   for (i = arg_count-1;  i >= next_arg; i--) {
  703. X      arg = arg_vector[i];
  704. X#ifdef FOLD
  705. X      strlwr(pathname); strlwr(arg);
  706. X#endif
  707. X#ifdef DEBUG
  708. Xprintf("needed: testing [%s] and [%s]\n", pathname, arg);
  709. X#endif
  710. X      if (STRCMP(arg,==,"+"))
  711. X         return (0);
  712. X
  713. X      /* If the argument contains a slash, the match fails if the
  714. X         path prefixes don't match */
  715. X      if (strchr(arg, *PATH_CH) != NULL) {      /* found slash */
  716. X         strcpy(arg_copy,arg);
  717. X         strcpy(path_copy,pathname);
  718. X         p = findlast(arg_copy, PATH_CH);
  719. X         if (p != NULL)
  720. X            *p = '\0';
  721. X            else {
  722. X                p = findlast (arg_copy, VER_INPUT);
  723. X                if (p != NULL)
  724. X                    *p = '\0';
  725. X            }
  726. X         p = findlast(path_copy, PATH_CH);
  727. X         if (p != NULL)
  728. X            *p = '\0';
  729. X            else {
  730. X                p = findlast (path_copy, VER_DISPLAY);
  731. X                if (p != NULL)
  732. X                    *p = '\0';
  733. X            }
  734. X         if (!match_half(path_copy, arg_copy)) {
  735. X#ifdef DEBUG
  736. Xprintf ("needed(): match failed for [%s] and [%s]\n",
  737. X    path_copy, arg_copy);
  738. X#endif
  739. X            continue;                     /* no match this time in loop */
  740. X         }
  741. X      }
  742. X
  743. X      /*
  744. X      We reach here either if the pattern had no slashes, or if it had a 
  745. X        slash but the path prefixes matched.  Now we will test to see if the 
  746. X        filename parts match.  If the argument contains VER_INPUT character, 
  747. X        then this separates the filename from a version number, and only that 
  748. X        specific version will match.  If not, then only the latest version 
  749. X        will match.  However, if the argument has a version character but
  750. X        nothing following it, that matches all versions.  Also, version
  751. X        0 matches only the latest version and version ^0 matches all
  752. X        versions except the latest one.
  753. X      */
  754. X        strcpy (arg_copy, arg);                            /* local copy of argument */
  755. X        strcpy (path_copy, pathname);                    /* local copy of pathname */
  756. X        p = findlast(arg_copy, VER_INPUT);            /* p is version in argument */
  757. X        q = findlast(path_copy, VER_DISPLAY);        /* q is version in archive */
  758. X        if (p != NULL && p != lastptr(arg_copy)) {/* nonnull version in arg */
  759. X            if (q != NULL) {                                /* nonnull ver. in archive */
  760. X                char *pp = p+1;                            /* point to actual version */
  761. X                char *qq = q+1;
  762. X                if (STRCMP(pp, ==, "0") && !(direntry->vflag & VFL_LAST) ||
  763. X                     STRCMP(pp, ==, "^0") && (direntry->vflag & VFL_LAST)) {
  764. X                        debug(("needed:  no match versions [%s] and [%s]\n", qq, pp))
  765. X                        continue;
  766. X                }
  767. X                if (STRCMP(pp, !=, "0") && STRCMP(pp, !=, "^0") &&
  768. X                    !match_half (qq, pp)) {
  769. X                    debug(("needed:  no match versions [%s] and [%s]\n", qq, pp))
  770. X                    continue;                                    /* no match this loop */
  771. X                }
  772. X            }
  773. X        }
  774. X        /* Special case test:  If argument has version but no filename,
  775. X            then filename is assumed to match */
  776. X        if (p == arg_copy) {                                /* 1st char is version char */
  777. X            return (1);                                        /* .. so declare a match */
  778. X        }
  779. X
  780. X        /* 
  781. X        Reach here if argument has no version character, or if argument has 
  782. X        version character and it matches version in pathname.  Now we check to 
  783. X        see if argument has no version character and if pathname is latest 
  784. X        version.  If so, the versions do match;  if not, then the match fails.  
  785. X        But if version numbering is not enabled, then versions always match.
  786. X        If the match fails, we do a "continue", else we fall through and
  787. X        proceed to test the filenames.  (Note:  It is intuitively better
  788. X        to first compare filenames and then see if versions match, but
  789. X        since they are both just independent fields, it's equally correct
  790. X        to compare versions first, as we are doing here, and then see if
  791. X        filenames match.  It may even be more efficient.)
  792. X        */
  793. X
  794. X        if (p == NULL &&                                         /* no version char typed */
  795. X                !(                                                    /* NOT */
  796. X                    (direntry->vflag & VFL_ON) == 0 ||     /*  no versions */
  797. X                    (direntry->vflag & VFL_LAST) ||        /*  .. or latest version */
  798. X                    q == NULL                                    /*  .. or no version char */
  799. X                )
  800. X            )
  801. X        {
  802. X#ifdef DEBUG
  803. Xprintf("needed: fail--no version typed and not latest version\n");
  804. X#endif
  805. X            continue;                                            /* match fails */
  806. X        } 
  807. X        /* versions match and we fall through */;
  808. X
  809. X        /* reach here if versions match -- so strip them and compare rest */
  810. X        if (p != NULL)
  811. X            *p = '\0';                            /* strips version from arg_copy */
  812. X        if (q != NULL)
  813. X            *q = '\0';                            /* strips version from path_copy */
  814. X
  815. X        justname = nameptr(path_copy);        /* filename without any pathname */
  816. X      if (match_half (justname, nameptr(arg_copy)))
  817. X         return (1);
  818. X#ifdef DEBUG
  819. Xprintf ("needed: fname-only match failed [%s] and [%s]\n",
  820. X justname, nameptr(arg_copy));
  821. X#endif
  822. X
  823. X      /* try for a character range */
  824. X      if (match_half (arg, "?-?")) {             /* character range given */
  825. X         if (arg[0] <= *justname && arg[2] >= *justname)
  826. X            return (1);
  827. X      }
  828. X   }
  829. X   return (0);
  830. X
  831. X} /* needed */
  832. X
  833. X/***********************/
  834. X/*
  835. Xmatch_half() compares a pattern with a string.  Wildcards accepted in
  836. Xthe pattern are:  "*" for zero or more arbitrary characters;  "?"
  837. Xfor any one characters.  Unlike the MS-DOS wildcard match, "*" is
  838. Xcorrectly handled even if it isn't at the end of the pattern. ".'
  839. Xis not special.
  840. X
  841. XOriginally written by Jeff Damens of Columbia University Center for
  842. XComputing Activities.  Taken from the source code for C-Kermit version
  843. X4C.
  844. X*/
  845. X
  846. Xint match_half (string, pattern) 
  847. Xregister char *string, *pattern;
  848. X{
  849. X   char *psave,*ssave;        /* back up pointers for failure */
  850. X   psave = ssave = NULL;
  851. X   while (1) {
  852. X#ifdef IGNORECASE
  853. X      for (; 
  854. X         tolower(*pattern) == tolower(*string); 
  855. X         pattern++,string++                        )  /* skip first */
  856. X#else
  857. X      for (; *pattern == *string; pattern++,string++)  /* skip first */
  858. X#endif /* IGNORECASE */
  859. X
  860. X         if (*string == '\0') 
  861. X            return(1);                          /* end of strings, succeed */
  862. X      if (*string != '\0' && *pattern == '?') {
  863. X         pattern++;                             /* '?', let it match */
  864. X         string++;
  865. X      } else if (*pattern == '*') {             /* '*' ... */
  866. X         psave = ++pattern;                     /* remember where we saw it */
  867. X         ssave = string;                        /* let it match 0 chars */
  868. X      } else if (ssave != NULL && *ssave != '\0') {   /* if not at end  */
  869. X         /* ...have seen a star */
  870. X         string = ++ssave;                      /* skip 1 char from string */
  871. X         pattern = psave;                       /* and back up pattern */
  872. X      } else 
  873. X         return(0);                             /* otherwise just fail */
  874. X   }
  875. X}
  876. X
  877. END_OF_FILE
  878. if test 8256 -ne `wc -c <'needed.c'`; then
  879.     echo shar: \"'needed.c'\" unpacked with wrong size!
  880. fi
  881. # end of 'needed.c'
  882. fi
  883. if test -f 'nextfile.c' -a "${1}" != "-c" ; then 
  884.   echo shar: Will not clobber existing file \"'nextfile.c'\"
  885. else
  886. echo shar: Extracting \"'nextfile.c'\" \(8490 characters\)
  887. sed "s/^X//" >'nextfile.c' <<'END_OF_FILE'
  888. X#ifndef LINT
  889. Xstatic char sccsid[]="@(#) nextfile.c 2.2 87/12/26 12:23:43";
  890. X#endif /* LINT */
  891. X
  892. X#include "options.h"
  893. X/*
  894. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  895. X*/
  896. X/*
  897. XFunctions to collect filenames from command line etc.  Nextfile() is
  898. Xused by both Atoz and Zoo.  Wildcard expansion by nextfile() is specific to 
  899. XMS-DOS and this implementation is specific to Microsoft C.  If the symbol 
  900. XPORTABLE is defined, nextfile() becomes effectively a no-op that will return
  901. Xthe original filespec the first time and NULL subsequently.
  902. X*/
  903. X
  904. X#define  FMAX  3        /* Number of different filename patterns */
  905. X
  906. X#ifndef    OK_STDIO
  907. X#include <stdio.h>
  908. X#define    OK_STDIO
  909. X#endif
  910. X#include "various.h"
  911. X#include "zoo.h"        /* solely to define PATHSIZE */
  912. X
  913. X#ifdef PORTABLE
  914. X#ifndef SPECNEXT
  915. X/* If portable version, nextfile() is effectively a no-op and any wildcard
  916. Xexpansion must be done by the runtime system before the command line
  917. Xis received by this program
  918. X*/
  919. Xchar *nextfile (what, filespec, fileset)
  920. Xint what;                        /* whether to initialize or match      */
  921. Xregister char *filespec;         /* filespec to match if initializing   */
  922. Xregister int fileset;            /* which set of files                  */
  923. X{
  924. X   static int first_time [FMAX+1];
  925. X   static char saved_fspec [FMAX+1][PATHSIZE];  /* our own copy of filespec */
  926. X
  927. X   if (what == 0) {
  928. X      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
  929. X      first_time[fileset] = 1;
  930. X      return (NULL);
  931. X   }
  932. X
  933. X   if (first_time[fileset]) {
  934. X      first_time[fileset] = 0;
  935. X      return (saved_fspec[fileset]);
  936. X   } else {
  937. X      return (NULL);
  938. X   }
  939. X}
  940. X#endif /* SPECNEXT */
  941. X#else
  942. X/* if not PORTABLE  then */
  943. X
  944. X#include "intdos.h"     /* registers for MS-DOS interrupts              */
  945. X#include "dta.h"        /* format of MS-DOS disk transfer area (dta)    */
  946. X#include "assert.h"     /* macro definition:  assert() macro            */
  947. X
  948. Xvoid setdta (struct dta_t *);
  949. Xvoid fcbpath (struct dta_t *, char *, char *);
  950. X
  951. X
  952. X/*******************/
  953. X/*
  954. Xnextfile() returns the name of the next source file matching a filespec.
  955. X
  956. XINPUT
  957. X   what: A flag specifying what to do.  If "what" is 0, nextfile() 
  958. X      initializes itself.  If "what" is 1, nextfile() returns the next 
  959. X      matching filename.  
  960. X   filespec:  The filespec, usually containing wildcard characters, that 
  961. X      specifies which files are needed.  If "what" is 0, filespec must be 
  962. X      the filespec for which matching filenames are needed.  If "what" is 1, 
  963. X      nextfile() does not use "filespec" and "filespec" should be NULL to 
  964. X      avoid an assertion error during debugging.
  965. X   fileset:  nextfile() can keep track of more than one set of filespecs.
  966. X      The fileset specifies which filespec is being matched and therefore
  967. X      which set of files is being considered.  "fileset" can be in the
  968. X      range 0:FMAX.  Initialization of one fileset does not affect the
  969. X      other filesets.
  970. X
  971. XOUTPUT
  972. X   IF what == 0 THEN
  973. X      return value is NULL
  974. X   ELSE IF what == 1 THEN
  975. X      IF a matching filename is found THEN
  976. X         return value is pointer to matching filename including supplied path
  977. X      ELSE
  978. X         IF at least one file matched previously but no more match THEN
  979. X            return value is NULL
  980. X         ELSE IF supplied filespec never matched any filename THEN
  981. X            IF this is the first call with what == 1 THEN
  982. X               return value is pointer to original filespec
  983. X            ELSE
  984. X               return value is NULL
  985. X            END IF
  986. X         END IF
  987. X      END IF
  988. X   END IF
  989. X
  990. XNOTE
  991. X
  992. X   Initialization done when "what"=0 is not dependent on the correctness
  993. X   of the supplied filespec but simply initializes internal variables
  994. X   and makes a local copy of the supplied filespec.  If the supplied
  995. X   filespec was illegal, the only effect is that the first time that
  996. X   nextfile() is called with "what"=1, it will return the original 
  997. X   filespec instead of a matching filename.  That the filespec was
  998. X   illegal will become obvious when the caller attempts to open the
  999. X   returned filename for input/output and the open attempt fails.
  1000. X
  1001. XUSAGE HINTS
  1002. X
  1003. Xnextfile() can be used in the following manner:
  1004. X
  1005. X      char *filespec;                  -- will point to filespec
  1006. X      char *this_file;                 -- will point to matching filename
  1007. X      filespec = parse_command_line(); -- may contain wildcards
  1008. X      FILE *stream;
  1009. X   
  1010. X      nextfile (0, filespec, 0);          -- initialize fileset 0
  1011. X      while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) {
  1012. X         stream = fopen (this_file, "whatever");
  1013. X         if (stream == NULL)
  1014. X            printf ("could not open %s\n", this_file);
  1015. X         else
  1016. X            perform_operations (stream);
  1017. X      }
  1018. X*/             
  1019. X               
  1020. Xchar *nextfile (what, filespec, fileset)
  1021. Xint what;                        /* whether to initialize or match      */
  1022. Xregister char *filespec;         /* filespec to match if initializing   */
  1023. Xregister int fileset;            /* which set of files                  */
  1024. X{
  1025. X   static struct dta_t new_dta [FMAX+1];     /* our own private dta        */
  1026. X   static int first_time [FMAX+1];
  1027. X   static char pathholder [FMAX+1][PATHSIZE]; /* holds a pathname to return */
  1028. X   static char saved_fspec [FMAX+1][PATHSIZE];/* our own copy of filespec   */
  1029. X   union REGS regs;
  1030. X
  1031. X   assert(fileset >= 0 && fileset <= FMAX);
  1032. X   if (what == 0) {
  1033. X      assert(filespec != NULL);
  1034. X      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
  1035. X      first_time[fileset] = 1;
  1036. X      return (NULL);
  1037. X   }
  1038. X
  1039. X   setdta (&new_dta[fileset]);   /* set new dta -- our very own */      
  1040. X   assert(what == 1);
  1041. X   assert(filespec == NULL);
  1042. X   assert(first_time[fileset] == 0 || first_time[fileset] == 1);
  1043. X
  1044. X   if (first_time[fileset]) {             /* first time -- initialize etc. */
  1045. X      /* find first matching file */
  1046. X      regs.h.ah = 0x4e;                   /* FindFirst DOS call      */
  1047. X      regs.x.dx = (unsigned int) saved_fspec[fileset]; /* filespec to match */
  1048. X      regs.x.cx = 0;                      /* search attributes       */
  1049. X      intdos (®s, ®s);
  1050. X   } else {
  1051. X      /* find next matching file */
  1052. X      regs.h.ah = 0x4f;                   /* FindNext DOS call       */
  1053. X      intdos (®s, ®s);
  1054. X   }
  1055. X
  1056. X   if (regs.x.carry != 0) {            /* if error status                  */
  1057. X      if (first_time[fileset]) {       /*   if file never matched then     */
  1058. X         first_time[fileset] = 0;
  1059. X         return (saved_fspec[fileset]);/*      return original filespec    */
  1060. X      } else {                         /*   else                           */
  1061. X         first_time[fileset] = 0;      /*                                  */
  1062. X         return (NULL);                /*      return (NULL) for no more   */
  1063. X      }
  1064. X   } else {                                        /* a file matched */
  1065. X      first_time[fileset] = 0;         
  1066. X      /* add path info  */
  1067. X      fcbpath (&new_dta[fileset], saved_fspec[fileset], pathholder[fileset]); 
  1068. X      return (pathholder[fileset]);                /* matching path  */
  1069. X   }
  1070. X} /* nextfile */
  1071. X
  1072. X/*******************/
  1073. X/* This function sets the dta to a new dta */
  1074. Xvoid setdta (dta)
  1075. Xstruct dta_t *dta;
  1076. X{
  1077. X   union REGS regs;
  1078. X   regs.h.ah = 0x1a;                /* SetDTA Call       */
  1079. X   regs.x.dx = (unsigned int) dta;  /* new DTA address   */
  1080. X   intdos (®s, ®s);
  1081. X}
  1082. X
  1083. X/*******************/
  1084. X/* 
  1085. Xfcbpath() accepts a pointer to the Disk Transfer Area (the DTA format is
  1086. Xdescribed on page 131 of Tandy-1000 programmers reference manual), a
  1087. Xcharacter pointer to a pathname that may contain wildcards, and a character
  1088. Xpointer to a buffer.  Copies into buffer the path prefix from the pathname
  1089. Xand the filename prefix from the DTA so that it forms a complete path
  1090. X*/
  1091. X
  1092. Xvoid fcbpath (dta, old_path, new_path)
  1093. Xstruct dta_t *dta;
  1094. Xchar *old_path;
  1095. Xregister char *new_path;
  1096. X{
  1097. X   register int i;
  1098. X   int length, start_pos;
  1099. X      
  1100. X   strcpy(new_path, old_path);               /* copy the whole thing first */
  1101. X   length = strlen(new_path);
  1102. X   i = length - 1;                           /* i points to end of path */
  1103. X   while (i >= 0 && new_path[i] != '/' && new_path[i] != '\\' && new_path[i] != ':')
  1104. X      i--;
  1105. X   /* either we found a "/", "\", or ":", or we reached the beginning of
  1106. X      the name.  In any case, i points to the last character of the
  1107. X      path part. */
  1108. X   start_pos = i + 1;
  1109. X   for (i = 0; i < 13; i++)
  1110. X      new_path[start_pos+i] = dta->fname[i];
  1111. X   new_path[start_pos+13] = '\0';
  1112. X}
  1113. X#endif /* PORTABLE */
  1114. X
  1115. END_OF_FILE
  1116. if test 8490 -ne `wc -c <'nextfile.c'`; then
  1117.     echo shar: \"'nextfile.c'\" unpacked with wrong size!
  1118. fi
  1119. # end of 'nextfile.c'
  1120. fi
  1121. if test -f 'zooadd2.c' -a "${1}" != "-c" ; then 
  1122.   echo shar: Will not clobber existing file \"'zooadd2.c'\"
  1123. else
  1124. echo shar: Extracting \"'zooadd2.c'\" \(8463 characters\)
  1125. sed "s/^X//" >'zooadd2.c' <<'END_OF_FILE'
  1126. X#ifndef LINT
  1127. X/* @(#) zooadd2.c 2.14 88/01/27 10:40:32 */
  1128. Xstatic char sccsid[]="@(#) zooadd2.c 2.14 88/01/27 10:40:32";
  1129. X#endif /* LINT */
  1130. X
  1131. X/*
  1132. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  1133. X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
  1134. X*/
  1135. X#include "options.h"
  1136. X#include "zoo.h"
  1137. X#ifndef    OK_STDIO
  1138. X#include <stdio.h>
  1139. X#define    OK_STDIO
  1140. X#endif
  1141. X#include "various.h"
  1142. X#include "zooio.h"
  1143. X#include "zoofns.h"
  1144. X#include "errors.i"
  1145. X#include "assert.h"
  1146. X#include "debug.h"
  1147. X#include "parse.h"
  1148. X
  1149. X/*
  1150. XMiscellaneous routines to support zooadd().
  1151. X*/
  1152. X
  1153. X/****************
  1154. XThis function is called with zoo_file positioned to the first
  1155. Xdirectory entry in an archive.  It skips past all existing files,
  1156. Xcounts the number of deleted files, saves the latest data and time
  1157. Xencountered, and adds all filenames encountered to a global list. The
  1158. Xlong filename is added if available, else the MSDOS filename is
  1159. Xadded.  
  1160. X*/
  1161. X
  1162. Xvoid skip_files (zoo_file, latest_date, latest_time, delcount, 
  1163. X                  latest_name, latest_pos)
  1164. XZOOFILE zoo_file;
  1165. Xunsigned int *latest_date, *latest_time;
  1166. Xint *delcount;
  1167. Xchar latest_name[];
  1168. Xlong *latest_pos;
  1169. X{
  1170. X   long save_offset, next_ptr;
  1171. X   struct direntry direntry;
  1172. X   struct direntry *drp = &direntry;
  1173. X
  1174. X   *latest_pos = 0L;
  1175. X   do {
  1176. X      /* read a directory entry */
  1177. X      save_offset = zootell (zoo_file);     /* save pos'n of this dir entry */
  1178. X      readdir (&direntry, zoo_file, 1);   /* read directory entry */
  1179. X      if (drp->next == 0L) {                 /* END OF CHAIN */
  1180. X         zooseek (zoo_file, save_offset, 0);      /* back up */
  1181. X         break;                                 /* EXIT on end of chain */
  1182. X      } else
  1183. X         *latest_pos = save_offset;
  1184. X      /* remember most recent date and time, for files not marked deleted */
  1185. X      if (!drp->deleted)
  1186. X         if (drp->date > *latest_date ||
  1187. X            (drp->date == *latest_date && drp->time > *latest_time)) {
  1188. X               *latest_date = drp->date;
  1189. X               *latest_time = drp->time;
  1190. X         }
  1191. X      next_ptr = drp->next;            /* ptr to next dir entry */
  1192. X      if (drp->deleted)
  1193. X         ++(*delcount);                      /* count deleted entries */
  1194. X      /* add name of file and position of direntry into global list */
  1195. X      /* but only if the entry is not deleted */
  1196. X      if (!drp->deleted) {
  1197. X#ifdef FOLD
  1198. X            /* IS THIS REALLY NEEDED?  IF SO, WHAT ABOUT drp->lfname? */
  1199. X         strlwr(drp->fname);
  1200. X#endif
  1201. X            /* add full pathname to global list */
  1202. X            strcpy (latest_name, fullpath (drp));
  1203. X         addfname (latest_name, save_offset, drp->date, drp->time,
  1204. X                            drp->vflag, drp->version_no);
  1205. X      }
  1206. X      zooseek (zoo_file, next_ptr, 0);   /* ..seek to next dir entry */
  1207. X   } while (next_ptr != 0L);              /* loop terminates on null ptr */
  1208. X}
  1209. X
  1210. X/*******************/
  1211. X/* kill_files() deletes all files in the supplied list of pointers to
  1212. Xfilenames */
  1213. X
  1214. Xint kill_files (flist, pathlength)
  1215. Xchar *flist[];                      /* list of ptrs to input fnames */
  1216. Xint pathlength;                     /* length of longest pathname */
  1217. X{
  1218. X   int status = 0;
  1219. X   int fptr;
  1220. X   prterror ('M', "-----\nErasing added files...\n");
  1221. X   for (fptr = 0;  flist[fptr] != NULL; fptr++) {
  1222. X#ifdef CHEKUDIR
  1223. X                if (isuadir(flist[fptr]))
  1224. X                    continue;
  1225. X#else /* CHEKUDIR */
  1226. X# ifdef CHEKDIR
  1227. X                if (isfdir(flist[fptr]))
  1228. X                    continue;
  1229. X# endif /* CHEKDIR */
  1230. X#endif /* CHEKUDIR */
  1231. X      prterror ('m', "%-*s -- ", pathlength, flist[fptr]);
  1232. X      if (unlink (flist[fptr]) == 0) {
  1233. X         prterror ('M', "erased\n");
  1234. X      } else {
  1235. X         prterror ('w', "Could not erase %s.\n", flist[fptr]);
  1236. X         status = 1;
  1237. X      }
  1238. X   }
  1239. X   return (status);
  1240. X}
  1241. X
  1242. X#ifndef PORTABLE
  1243. X/*******************/
  1244. Xvoid copyfields (drp, thp)
  1245. Xstruct direntry *drp;
  1246. Xstruct tiny_header *thp;
  1247. X{
  1248. X   drp->org_size = thp->org_size;
  1249. X   drp->file_crc = thp->file_crc;
  1250. X   drp->size_now = thp->size_now;
  1251. X   drp->major_ver = thp->major_ver;
  1252. X   drp->minor_ver = thp->minor_ver;
  1253. X}
  1254. X#endif
  1255. X
  1256. X/*******************/
  1257. X/* processes option switches for zooadd() */
  1258. Xvoid opts_add (option, zootime, quiet, suppress, move, new, pack,
  1259. X          update, add_comment, z_fmt, need_dir, inargs, genson)
  1260. Xchar *option;
  1261. Xint *zootime, *quiet, *suppress, *move, *new, *pack,
  1262. X   *update, *add_comment, *z_fmt, *need_dir, *inargs,
  1263. X    *genson;
  1264. X
  1265. X{
  1266. X   if (*option == 'T') {
  1267. X      (*zootime)++;
  1268. X      option++;
  1269. X      while (*option) {
  1270. X         switch (*option) {
  1271. X            case 'q': (*quiet)++; break;
  1272. X            default:
  1273. X               prterror ('f', inv_option, *option);
  1274. X         }
  1275. X      option++;
  1276. X      }
  1277. X   }
  1278. X   
  1279. X   while (*option) {
  1280. X      switch (*option) {
  1281. X         case 'a': break;  
  1282. X         case 'f': (*suppress)++; break;        /* suppress compression */
  1283. X         case 'M': (*move)++; break;            /* delete files after adding them */
  1284. X         case 'n': (*new)++; break;             /* add only files not in archive */
  1285. X         case 'P': (*pack)++; break;            /* pack after adding */
  1286. X         case 'u': (*update)++;   break;        /* add only files already in archive */
  1287. X         case 'q': (*quiet)++; break;           /* be quiet */
  1288. X         case 'c': (*add_comment)++; break;     /* add comment */
  1289. X         case ':': *need_dir = 0; break;        /* don't store directories */
  1290. X         case 'I': (*inargs)++; break;            /* get filenames from stdin */
  1291. X/* #ifdef PORTABLE */ /* avoid Turbo C warning about unused param */
  1292. X         case 'z': (*z_fmt)++; break;           /* look for Z format files */
  1293. X/* #endif */
  1294. X            case '+': 
  1295. X                        *genson = 1;  break;
  1296. X            case '-': 
  1297. X                        *genson = 0;  break;
  1298. X         default:
  1299. X            prterror ('f', inv_option, *option);
  1300. X      }
  1301. X      option++;
  1302. X   } /* end while */
  1303. X}
  1304. X
  1305. X
  1306. X/* 
  1307. XStores long filename into direntry.lfname iff it is different from MSDOS
  1308. Xfilename.  Also stores directory name if need_dir is true.  Moved out of 
  1309. Xzooadd() so zooadd() doesn't get too big for optimization.
  1310. X*/
  1311. Xvoid storefname (direntry, this_path, need_dir)
  1312. Xstruct direntry *direntry;
  1313. Xchar *this_path;
  1314. Xint need_dir;
  1315. X{
  1316. X   struct path_st path_st;
  1317. X   parse (&path_st, this_path);
  1318. X   direntry->lfname[0] = '\0';
  1319. X   direntry->namlen = 0;
  1320. X#ifdef SPECMOD
  1321. X   specfname (path_st.lfname);
  1322. X   specdir (path_st.dir);
  1323. X#endif
  1324. X   if (strcmp(path_st.lfname,direntry->fname) != 0) {
  1325. X         strcpy (direntry->lfname, path_st.lfname); /* full filename */
  1326. X         direntry->namlen = strlen(direntry->lfname) + 1;
  1327. X   }
  1328. X   if (need_dir) {
  1329. X      strcpy (direntry->dirname, path_st.dir);   /* directory name */
  1330. X      direntry->dirlen = strlen(direntry->dirname) + 1;
  1331. X      if (direntry->dirlen == 1) /* don't store trailing null alone */
  1332. X         direntry->dirlen = 0;
  1333. X   } else {
  1334. X      direntry->dirname[0] = '\0';
  1335. X      direntry->dirlen = 0;
  1336. X   }
  1337. X}
  1338. X
  1339. X/* 
  1340. XFunction getsdtin() gets a pathname from standard input, cleans
  1341. Xit if necessary by removing any following blanks/tabs and other
  1342. Xjunk, and returns it in a static area that is overwritten by each
  1343. Xcall.
  1344. X*/
  1345. Xchar *getstdin()
  1346. X{
  1347. X    char *chptr;                                    /* temp pointer */
  1348. X    static char tempname[PATHSIZE];
  1349. X    do {
  1350. X        if (fgets (tempname, PATHSIZE, stdin) == NULL)
  1351. X            return (NULL);
  1352. X        /* remove trailing blank, tab, newline */
  1353. X        for (chptr = tempname; *chptr != '\0';  chptr++) {
  1354. X            if (
  1355. X    /* PURIFY means remove trailing blanks/tabs and all subsequent chars */
  1356. X#ifdef PURIFY
  1357. X                    *chptr == '\t' || *chptr == ' ' ||
  1358. X#endif
  1359. X                    *chptr == '\n'                        /* always remove trailing \n */
  1360. X                )
  1361. X            {
  1362. X    
  1363. X                *chptr = '\0';
  1364. X                break;
  1365. X            }
  1366. X        }
  1367. X    } while (*tempname == '\0');                /* get a nonempty line */
  1368. X#ifdef FOLD
  1369. X    strlwr (tempname);
  1370. X#endif
  1371. X    return (tempname);
  1372. X}
  1373. X
  1374. X/* 
  1375. XFunction newdir() adds some default information to a directory entry.
  1376. XThis will be a new directory entry added to an archive.
  1377. X*/
  1378. Xvoid newdir (direntry)
  1379. Xregister struct direntry *direntry;
  1380. X{
  1381. X#ifdef GETTZ
  1382. X    long gettz();
  1383. X#endif
  1384. X   direntry->zoo_tag = ZOO_TAG;
  1385. X   direntry->type = 2;                  /* type is now 2 */
  1386. X#ifdef GETTZ
  1387. X    direntry->tz = (uchar) (gettz() / (15 * 60)); /* seconds => 15-min units */
  1388. X#else
  1389. X   direntry->tz = NO_TZ;                /* timezone unknown */
  1390. X#endif
  1391. X   direntry->struc = 0;                 /* unstructured file */
  1392. X   direntry->system_id = SYSID_NIX;     /* identify **IX filesystem */
  1393. X    direntry->vflag = VFL_ON|VFL_LAST;     /* latest version */
  1394. X    direntry->version_no = 1;                    /* begin with version 1 */
  1395. X    /* 1 for namlen, 1 for dirlen, 2 for system id, 3 for attributes,
  1396. X        1 for version flag and 2 for version number */
  1397. X   direntry->var_dir_len = direntry->dirlen + direntry->namlen + 10;
  1398. X}
  1399. END_OF_FILE
  1400. if test 8463 -ne `wc -c <'zooadd2.c'`; then
  1401.     echo shar: \"'zooadd2.c'\" unpacked with wrong size!
  1402. fi
  1403. # end of 'zooadd2.c'
  1404. fi
  1405. echo shar: End of archive 4 \(of 10\).
  1406. cp /dev/null ark4isdone
  1407. MISSING=""
  1408. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1409.     if test ! -f ark${I}isdone ; then
  1410.     MISSING="${MISSING} ${I}"
  1411.     fi
  1412. done
  1413. if test "${MISSING}" = "" ; then
  1414.     echo You have unpacked all 10 archives.
  1415.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1416. else
  1417.     echo You still need to unpack the following archives:
  1418.     echo "        " ${MISSING}
  1419. fi
  1420. ##  End of shell archive.
  1421. exit 0
  1422.